package com.duolebo.uteped_sdk.ota;

import static com.actions.aticonsota.OtaStatus.STATE_IDLE;
import static com.actions.aticonsota.OtaStatus.STATE_TRANSFERRING;
import static com.actions.ibluz.factory.BluzDeviceFactory.KeyUUIDS.keyReadCharacteristicUUID;
import static com.actions.ibluz.factory.BluzDeviceFactory.KeyUUIDS.keyServiceUUID;
import static com.actions.ibluz.factory.BluzDeviceFactory.KeyUUIDS.keyWriteCharacteristicUUID;

import android.annotation.SuppressLint;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;

import androidx.annotation.NonNull;

import com.actions.aticonsota.OTAManager;
import com.actions.aticonsota.OtaStatus;
import com.actions.ibluz.factory.BluzDeviceFactory;
import com.actions.ibluz.factory.IBluzDevice;
import com.actions.ibluz.util.RemoteStatus;
import com.duolebo.uteped_sdk.utils.DeviceHelper;
import com.yc.nadalsdk.ble.open.UteBleClient;
import com.yc.nadalsdk.listener.GattCallbackListener;
import com.yc.nadalsdk.log.LogUtils;
import com.yc.nadalsdk.utils.open.SPUtil;

import java.util.HashMap;
import java.util.UUID;

/**
 * 炬芯平台OTA工具类
 */
public class ActsOta extends BaseOemOta {
    private final static String TAG = "ActsOtaUtil---";
    private static final String BLE_UUID_SERVICE = "e49a25f8-f69a-11e8-8eb2-f2801f1b9fd1";
    private static final String BLE_UUID_SERVICE_WRITE = "e49a25e0-f69a-11e8-8eb2-f2801f1b9fd1";
    private static final String BLE_UUID_SERVICE_READ = "e49a28e1-f69a-11e8-8eb2-f2801f1b9fd1";
    private static UUID CLIENT_CHARACTERISTIC_CONFIGURATION = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");

    private IBluzDevice mBluzConnector;
    private OTAManager mOTAManager;
    private OtaStatus mOTAStatus = STATE_IDLE;

    private Context mContext;
    private String filePath;

    private static final int RELEASE_OTA_MSG = 1;
    private static final int PREPARE_MSG = 2;
    private static final int ON_OTA_STATE_MSG = 3;
    private static final int ON_OTA_PROGRESS_MSG = 4;
    private static final int ON_OTA_ERROR_MSG = 5;
    private final Handler mHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case RELEASE_OTA_MSG:
                    LogUtils.i(TAG, "升级成功，关闭通知，releaseOTA");
                    mBluzConnector.closeNotify();
                    releaseOTA();
                    break;
                case PREPARE_MSG:
                    prepare();
                    break;
                case ON_OTA_STATE_MSG:
                    if (mBleOtaListener != null) {
                        mBleOtaListener.onOtaStatus(msg.arg1);
                    }
                    break;
                case ON_OTA_PROGRESS_MSG:
                    if (mBleOtaListener != null) {
                        mBleOtaListener.onOTAProgress(msg.arg1);
                    }
                    break;
                case ON_OTA_ERROR_MSG:
                    if (mBleOtaListener != null) {
                        mBleOtaListener.onOTAError(msg.arg1, (String) msg.obj);
                    }
                    break;
            }
        }
    };

    public ActsOta(Context context) {
        this.mContext = context;
        LogUtils.i(TAG, "升级工具初始化");
    }

    private BleOtaListener mBleOtaListener;

    private void startOTA(String path) {
        LogUtils.i(TAG, "开始升级 mOTAStatus=" + mOTAStatus);
        filePath = path;
        if (TextUtils.isEmpty(filePath)) {
            LogUtils.i(TAG, "文件路径为空，返回失败");
            onFail(6, 0, "文件路径为空");
            return;
        }
        LogUtils.i(TAG, "开始升级 filePath=" + filePath);
        mOTAStatus = STATE_IDLE;
        LogUtils.i(TAG, "开始升级");
        initBluzDevice();
        Thread connectThread = new Thread() {
            @Override
            public void run() {
                super.run();
                connectService();
            }
        };
        connectThread.start();
    }

    @SuppressLint("MissingPermission")
    private void connectService() {
        BluetoothGatt mGatt = UteBleClient.getUteBleClient().getBluetoothGatt();
        LogUtils.i(TAG, "connectService mGatt=" + mGatt);
        HashMap<String, UUID> uuids = new HashMap<>();
        UteBleClient.getUteBleClient().getUteBleConnection().setOnGattCallbackListener(mCharacteristicChangedListener);
        uuids.put(keyServiceUUID, UUID.fromString(BLE_UUID_SERVICE));
        uuids.put(keyReadCharacteristicUUID, UUID.fromString(BLE_UUID_SERVICE_READ));
        uuids.put(keyWriteCharacteristicUUID, UUID.fromString(BLE_UUID_SERVICE_WRITE));
        mBluzConnector.connectServiceAndCharacteristic(uuids, mGatt, mOnServiceConnectListener);
    }

    //释放SDK资源，保证连接断开
    private void releaseOTA() {
        LogUtils.i(TAG, "releaseOTA");
        if (mOTAManager != null) {
            mOTAManager.release();
            mOTAManager = null;
        }

        if (mBluzConnector != null) {
            mBluzConnector = null;
        }
        mOTAStatus = STATE_IDLE;
        DeviceHelper.getInstance().setUpgrading(false);
        UteBleClient.getUteBleClient().getUteBleConnection().setOnGattCallbackListener(null);
//        instance = null;
    }

    private void initBluzDevice() {
        if (mBluzConnector != null) {
            mBluzConnector.release();
        }
        if (mOTAManager != null) {
            mOTAManager.cancel();
            mOTAManager.release();
        }

        mBluzConnector = BluzDeviceFactory.getDevice(mContext, BluzDeviceFactory.ConnectionType.BLE);

        mBluzConnector.setAutoConnectDataChanel(false);
        mOTAManager = new OTAManager(mContext, mBluzConnector.getIO());
        mOTAManager.setOTAListener(mOTAListener);
    }

    //准备
    private void prepare() {
        if (mOTAStatus == STATE_IDLE) {
            LogUtils.i(TAG, "Prepare path=" + filePath);
            if (filePath.length() == 0) {
                LogUtils.i(TAG, "请先设置OTA文件，再开始！");
                return;
            }
            boolean readFile = mOTAManager.setOTAFile(filePath);
            LogUtils.i(TAG, "Prepare readFile=" + readFile);
            if (!readFile) {
                LogUtils.i(TAG, "无法读取OTA文件！");
            }
            mOTAManager.prepare();
        } else {
            LogUtils.i(TAG, "状态异常，请稍后！");

        }
    }

    private void upgrade() {
        if (mOTAManager != null) {
            mOTAManager.upgrade();
        }
    }

    private void onFail(int where, int errCode, String errMsg) {
        LogUtils.e(TAG, "onFail " + where + "," + mBleOtaListener);
        Message message = new Message();
        message.what = ON_OTA_ERROR_MSG;
        message.arg1 = errCode;
        message.obj = errMsg;
        mHandler.sendMessage(message);
    }


    private final OTAManager.OTAListener mOTAListener = new OTAManager.OTAListener() {

        @Override
        public void onStatus(OtaStatus state) {
            LogUtils.i(TAG, "OTAListener-- onStatus= " + state);
            mOTAStatus = state;
            int mState = BleOtaListener.OTA_STATE_UNKNOWN;
            switch (state) {
                case STATE_IDLE:
                    LogUtils.i(TAG, "OTA status---待机");
                    mState = BleOtaListener.OTA_STATE_IDLE;
                    break;
                case STATE_PREPARED:
                    LogUtils.i(TAG, "OTA status---已准备完成,可以升级");
                    mState = BleOtaListener.OTA_STATE_PREPARED;
                    DeviceHelper.getInstance().setUpgrading(true);
                    mHandler.postDelayed(() -> {
                        upgrade();
                    }, 1000);
                    break;
                case STATE_PREPARING:
                    LogUtils.i(TAG, "OTA status---准备中");
                    mState = BleOtaListener.OTA_STATE_PREPARING;
                    break;
                case STATE_TRANSFERRING:
                    LogUtils.i(TAG, "OTA status---升级中");
                    mState = BleOtaListener.OTA_STATE_TRANSFERRING;
                    break;
                case STATE_UNKNOWN:
                    LogUtils.i(TAG, "OTA status---未知");
                    mState = BleOtaListener.OTA_STATE_UNKNOWN;
                    onFail(1, 0, "UNKNOWN");
                    releaseOTA();
                    break;
                case STATE_TRANSFERRED:
                    LogUtils.i(TAG, "OTA status---升级完成");
                    mState = BleOtaListener.OTA_STATE_TRANSFERRED;
                    mHandler.sendEmptyMessageDelayed(RELEASE_OTA_MSG, 200);
                    break;
                default:
                    break;
            }
            Message message = new Message();
            message.what = ON_OTA_STATE_MSG;
            message.arg1 = mState;
            mHandler.sendMessage(message);
        }

        @Override
        public void onAudioDataReceived(int psn, int len, byte[] data) {
//             LogUtils.i(TAG, "OTAListener-- onAudioDataReceived: " + psn + ", " + len + ", " + Utils.hexBuffer2String(data));
        }


        @Override
        public void onRemoteStatusReceived(RemoteStatus status) {
            LogUtils.i(TAG, "OTAListener-- onRemoteStatusReceived status" + status);
        }

        @Override
        public void onProgress(int progress, int total) {
            int pro = (int) (((double) progress / total) * 100);
            float prof = (float) progress / total;
            if (prof >= 0.999f) {
                progress = total;
                pro = 100;
            }
            LogUtils.i(TAG, "OTAListener-- onProgress progress=" + progress + ",total=" + total + "，百分之" + pro + ",prof=" + prof);
            if (total > 0) {
                Message message = new Message();
                message.what = ON_OTA_PROGRESS_MSG;
                message.arg1 = pro;
                mHandler.sendMessage(message);
            }
        }

        @Override
        public void onError(int errorCode, String errorMsg) {
            LogUtils.i(TAG, "OTAListener-- onError errorCode" + errorCode + ",errorMsg=" + errorMsg);
            releaseOTA();
            onFail(2, errorCode, errorMsg);
        }

        @Override
        public void onWriteBytes(int count) {
//            LogUtils.debug(TAG, "OTAListener-- onWriteBytes count" + count);
        }
    };

    private final IBluzDevice.OnServiceConnectListener mOnServiceConnectListener = new IBluzDevice.OnServiceConnectListener() {
        @Override
        public void onServiceConnected() {
            BluetoothGatt gatt = UteBleClient.getUteBleClient().getBluetoothGatt();
            LogUtils.i(TAG, "OTA SDK 设置通知成功 onServiceConnected. mtu=" + SPUtil.getInstance().getPhoneMtu());
            LogUtils.i(TAG, "connectService mGatt.getServices=" + gatt.getServices());
            mBluzConnector.setMtu(SPUtil.getInstance().getPhoneMtu());
            mHandler.sendEmptyMessageDelayed(PREPARE_MSG, 1500);
        }

        @Override
        public void onServiceConnectFail() {
            LogUtils.i(TAG, "OTA SDK 设置通知失败 onServiceConnectFail");
            if (mOTAManager != null) {
                mOTAManager.release();
                mOTAManager = null;
            }
            mOTAStatus = STATE_IDLE;
            releaseOTA();
            onFail(3, 0, "onServiceConnectFail");
        }
    };

    public GattCallbackListener mCharacteristicChangedListener = new GattCallbackListener() {
        @Override
        public void onConnectionStateChange(int status) {

        }

        @Override
        public void onCharacteristicChanged(BluetoothGatt bluetoothGatt, BluetoothGattCharacteristic characteristic) {
            if (mBluzConnector != null && characteristic.getUuid().equals(UUID.fromString(BLE_UUID_SERVICE_READ))) {
                mBluzConnector.readIndicator(characteristic);
            }
        }

        @Override
        public void onCharacteristicWrite(BluetoothGatt bluetoothGatt, BluetoothGattCharacteristic characteristic, int status) {
//            LogUtils.debug(TAG, "OTA onCharacteristicWrite status = " + status);
            if (mBluzConnector != null) {
                mBluzConnector.onWrite(bluetoothGatt, characteristic, status);
            }
        }
    };

    @Override
    public void oemPrepare() {
    }

    @Override
    public void oemStartOTA(String filePath, BleOtaListener listener) {
        mBleOtaListener = listener;
        startOTA(filePath);
    }

    @Override
    public void oemCancelOTA() {
        if (mOTAStatus == STATE_TRANSFERRING) {
            LogUtils.i(TAG, "取消升级");
            releaseOTA();
        }
    }

    @Override
    public void oemRelease() {
    }

    @Override
    public void oemBluetoothOff() {
        releaseOTA();
        onFail(4, 0, "Bluetooth OFF");
    }
}
